package com.zjw.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;


import com.zjw.annotation.domain.ResponseResult;
import com.zjw.annotation.domain.dto.AddUserDto;
import com.zjw.annotation.domain.dto.EditUserDto;
import com.zjw.annotation.domain.entity.Menu;
import com.zjw.annotation.domain.entity.Role;
import com.zjw.annotation.domain.entity.User;
import com.zjw.annotation.domain.vo.*;
import com.zjw.enums.AppHttpCodeEnum;
import com.zjw.mapper.UserMapper;
import com.zjw.service.MenuService;
import com.zjw.service.RoleService;
import com.zjw.service.UserService;
import com.zjw.utils.BeanCopyUtils;
import com.zjw.utils.SecurityUtil;
import io.jsonwebtoken.lang.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 用户表(User)表服务实现类
 *
 * @author makejava
 * @since 2023-12-13 17:46:27
 */
@Service("userService")
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private PasswordEncoder encoder;

    @Autowired
    private MenuService menuService;

    @Autowired
    private RoleService roleService;

    @Override
    public ResponseResult getUserInfo() {
        Long curUserId = SecurityUtil.getCurUserId();

        User user = getById(curUserId);
        UserInfoVo resUser = BeanCopyUtils.copy(user, UserInfoVo.class);
        return ResponseResult.okResult(resUser);
    }

    @Override
    public ResponseResult saveUserInfo(User user) {
        updateById(user);
        return ResponseResult.okResult();
    }


    @Override
    public ResponseResult register(User user) {
//        查询用户名是否已经存在
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUserName, user.getUserName());
        User one = getOne(wrapper);
        if (one != null) {
//            用户已经存在
            return ResponseResult.errorResult(AppHttpCodeEnum.USERNAME_EXIST);
        }
        user.setPassword(encoder.encode(user.getPassword()));
        save(user);
        return ResponseResult.okResult();
    }

    /**
     * 获取后台用户信息
     *
     * @return {@link ResponseResult}
     */
    @Override
    public ResponseResult getInfo() {
        Long curId = SecurityUtil.getCurUserId();
//        获取当前用户权限集合
        List<Menu> perms = menuService.getPermsById(curId);
        List<String> resPerms = perms.stream().map(r -> r.getPerms()).collect(Collectors.toList());
//        获取当前用户角色集合
        List<Role> roles = roleService.getRolesById(curId);
        List<String> resRoles = roles.stream().map(r -> r.getRoleKey()).collect(Collectors.toList());
//        获取当前用户
        User temp = SecurityUtil.getCurUser();
        UserInfoVo user = BeanCopyUtils.copy(temp, UserInfoVo.class);


        return ResponseResult.okResult(new AdminUserInfoVo(resPerms, resRoles, user));
    }

    /**
     * 生成当前用户的动态路由树形结构返回
     *
     * @return {@link ResponseResult}
     */
    @Override
    public ResponseResult getRouters() {

//        返回当前用户的所有权限菜单
        Long id = SecurityUtil.getCurUserId();

//        如果是管理员id返回所有菜单
        List<Menu> rawPerms = null;
        if (id.equals(1L) || id.equals(7L)) {
            System.out.println("----------------------全部权限菜单**********************");
            rawPerms = menuService.getTreeMenuAdmin();
        } else {
            rawPerms = menuService.getTreeMenuById(id);
        }


//        生成树形结构
        List<MenuTreeVo> res = buildTree(rawPerms);

        return ResponseResult.okResult(new RoutersVo(res));
    }

    private List<MenuTreeVo> buildTree(List<Menu> rawMenus) {
//        先创建根目录
        List<MenuTreeVo> res = rawMenus.stream().filter(m -> m.getParentId().equals(0L))
                .map(m -> {
                    MenuTreeVo copy = BeanCopyUtils.copy(m, MenuTreeVo.class);
//                    设置copy的子列表
                    copy.setChildren(getChildren(rawMenus, copy.getId()));
                    return copy;
                }).collect(Collectors.toList());
        return res;
    }

    private List<MenuTreeVo> getChildren(List<Menu> rawMenus, Long pId) {
        List<MenuTreeVo> res = rawMenus.stream().filter(m -> m.getParentId().equals(pId))
                .map(m -> {
                    MenuTreeVo copy = BeanCopyUtils.copy(m, MenuTreeVo.class);
//                    设置copy的子列表
                    copy.setChildren(getChildren(rawMenus, copy.getId()));
                    return copy;
                }).collect(Collectors.toList());
        return res;
    }


    /**
     * 获取用户列表 后台管理
     *
     * @param pageNum     页码
     * @param pageSize    页面大小
     * @param userName    用户名
     * @param phonenumber 电话号码
     * @param status      状态
     * @return {@link ResponseResult}
     */
    @Override
    public ResponseResult getUserList(Long pageNum, Long pageSize, String userName, String phonenumber, String status) {
//        封装条件
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        if (Strings.hasText(userName)) wrapper.like(User::getUserName, userName);
        if (Strings.hasText(phonenumber)) wrapper.eq(User::getPhonenumber, phonenumber);
        if (Strings.hasText(status)) wrapper.eq(User::getStatus, status);

//        封装分页
        IPage page = new Page(pageNum, pageSize);

        page(page, wrapper);

        return ResponseResult.okResult(new PageVo(BeanCopyUtils.copyList(page.getRecords(), UserListVo.class), page.getTotal()));
    }

    /**
     * 按 ID 获取用户
     * 返回当前用户的信息和所分配角色信息
     *
     * @param id 编号
     * @return {@link ResponseResult}
     */
    @Override
    public ResponseResult getUserById(Long id) {
        User user = getById(id);
        UserRoleVo res = new UserRoleVo();
        res.setUser(BeanCopyUtils.copy(user, UserRoleListUserVo.class));

//        获取所有有效权限列表
        res.setRoles(BeanCopyUtils.copyList(roleService.getAllValidRoleFunc(), RoleListVo.class));

//        获取当前用户所分配角色
        List<Role> rawRoleList = roleService.getAdminRolesById(id);
        List<String> roleIds = new ArrayList<>();
        rawRoleList.stream().forEach(r -> {
            roleIds.add(r.getId().toString());
        });

        res.setRoleIds(roleIds);
        return ResponseResult.okResult(res);
    }

    /**
     * 添加用户
     *
     * @param addUserDto 添加用户 DTO
     * @return {@link ResponseResult}
     */
    @Override
    public ResponseResult addUser(AddUserDto addUserDto) {
//        插入用户
        User user = BeanCopyUtils.copy(addUserDto, User.class);
        user.setType("1");
        user.setPassword(encoder.encode(user.getPassword()));
        if (!save(user)) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_INVALID_CHECK);
        }
//        分配角色
        roleService.assignRolesToUserById(user.getId(), addUserDto.getRoleIds());

        return ResponseResult.okResult();
    }

    @Override
    public ResponseResult editUser(EditUserDto editUserDto) {
//        尝试更新用户
        User user = BeanCopyUtils.copy(editUserDto, User.class);
        if (!updateById(user)) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_INVALID_CHECK);
        }

//        清空授权; 重新授权
        roleService.removeUserRoleByUserId(user.getId());
//        分配权限
        roleService.assignRolesToUserById(user.getId(), editUserDto.getRoleIds());
        return ResponseResult.okResult();
    }

    @Override
    public ResponseResult removeUser(List<Long> ids) {
        ids.stream().forEach(id -> {
            //        删除用户
            removeById(id);
//        删除分配角色信息
            roleService.removeUserRoleByUserId(id);
        });
        return ResponseResult.okResult();
    }

    @Override
    public ResponseResult changeStatus(Long userId, String status) {
        LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(User::getId, userId);
        wrapper.set(User::getStatus, status);
        return ResponseResult.okResult(update(wrapper));
    }
}

